#ifndef CHARACTERRECORD_H
#define CHARACTERRECORD_H

#include <QObject>
#include <QMap>

#include "DndData.h"

class CharacterRecord : public QObject
{
    Q_OBJECT

    // CHARACTER DETAILS
    Q_PROPERTY(QString name READ name WRITE setName)
    Q_PROPERTY(QString player READ player WRITE setPlayer)
    Q_PROPERTY(QString className READ className WRITE setClassName)
    Q_PROPERTY(QString paragonPath READ paragonPath WRITE setParagonPath)
    Q_PROPERTY(QString epicDestiny READ epicDestiny WRITE setEpicDestiny)
    Q_PROPERTY(QString totalXP READ totalXP WRITE setTotalXP)
    Q_PROPERTY(QString race READ race WRITE setRace)
    Q_PROPERTY(QString size READ size WRITE setSize)
    Q_PROPERTY(int age READ age WRITE setAge)
    Q_PROPERTY(QString gender READ gender WRITE setGender)
    Q_PROPERTY(QString height READ height WRITE setHeight)
    Q_PROPERTY(int heightInInches READ heightInInches WRITE setHeightInInches)
    Q_PROPERTY(QString weight READ weight WRITE setWeight)
    Q_PROPERTY(int weightInPounds READ weightInPounds WRITE setWeightInPounds)
    Q_PROPERTY(QString alignment READ alignment WRITE setAlignment)
    Q_PROPERTY(QString deity READ deity WRITE setDeity)
    Q_PROPERTY(QString company READ company WRITE setCompany)
    Q_PROPERTY(QString raceAndClass READ raceAndClass)

    // BASE STATS
    Q_PROPERTY(int strength READ strength WRITE setStrength)
    Q_PROPERTY(int constitution READ constitution WRITE setConstitution)
    Q_PROPERTY(int dexterity READ dexterity WRITE setDexterity)
    Q_PROPERTY(int intelligence READ intelligence WRITE setIntelligence)
    Q_PROPERTY(int wisdom READ wisdom WRITE setWisdom)
    Q_PROPERTY(int charisma READ charisma WRITE setCharisma)

    // LEVEL AND INITIATIVE
    Q_PROPERTY(int level READ level WRITE setLevel)
    Q_PROPERTY(int halfLevel READ halfLevel)
    Q_PROPERTY(int tenPlusHalfLevel READ tenPlusHalfLevel)
    Q_PROPERTY(int initiative READ initiative)
    Q_PROPERTY(int initiativeMiscMod READ initiativeMiscMod WRITE setInitiativeMiscMod)
    Q_PROPERTY(int initFeatBonus READ initFeatBonus WRITE setInitFeatBonus)

    // STATS AND MODIFIERS
    Q_PROPERTY(int strMod READ strMod)
    Q_PROPERTY(int conMod READ conMod)
    Q_PROPERTY(int dexMod READ dexMod)
    Q_PROPERTY(int intMod READ intMod)
    Q_PROPERTY(int wisMod READ wisMod)
    Q_PROPERTY(int chaMod READ chaMod)
    Q_PROPERTY(int strModPlusHalfLevel READ strModPlusHalfLevel)
    Q_PROPERTY(int conModPlusHalfLevel READ conModPlusHalfLevel)
    Q_PROPERTY(int dexModPlusHalfLevel READ dexModPlusHalfLevel)
    Q_PROPERTY(int intModPlusHalfLevel READ intModPlusHalfLevel)
    Q_PROPERTY(int wisModPlusHalfLevel READ wisModPlusHalfLevel)
    Q_PROPERTY(int chaModPlusHalfLevel READ chaModPlusHalfLevel)

    // DEFENCES
    Q_PROPERTY(int armourClass READ armourClass)
    Q_PROPERTY(int armourWeight READ armourWeight WRITE setArmourWeight)
    Q_PROPERTY(int armourPenalty READ armourPenalty WRITE setArmourPenalty)
    Q_PROPERTY(int acAbilBonus READ acAbilBonus)
    Q_PROPERTY(int acClassBonus READ acClassBonus WRITE setAcClassBonus)
    Q_PROPERTY(int acFeatBonus READ acFeatBonus WRITE setAcFeatBonus)
    Q_PROPERTY(int acMiscBonus1 READ acMiscBonus1 WRITE acMiscBonus1)
    Q_PROPERTY(int acMiscBonus2 READ acMiscBonus2 WRITE acMiscBonus2)
    Q_PROPERTY(int fortitude READ fortitude)
    Q_PROPERTY(int fortAbilBonus READ fortAbilBonus)
    Q_PROPERTY(int fortClassBonus READ fortClassBonus WRITE setFortClassBonus)
    Q_PROPERTY(int fortFeatBonus READ fortFeatBonus WRITE setFortFeatBonus)
    Q_PROPERTY(int fortMiscBonus1 READ fortMiscBonus1 WRITE setFortMiscBonus1)
    Q_PROPERTY(int fortMiscBonus2 READ fortMiscBonus2 WRITE setFortMiscBonus2)
    Q_PROPERTY(int reflex READ reflex)
    Q_PROPERTY(int refAbilBonus READ refAbilBonus)
    Q_PROPERTY(int refClassBonus READ refClassBonus WRITE setRefClassBonus)
    Q_PROPERTY(int refFeatBonus READ refFeatBonus WRITE setRefFeatBonus)
    Q_PROPERTY(int refMiscBonus1 READ refMiscBonus1 WRITE setRefMiscBonus1)
    Q_PROPERTY(int refMiscBonus2 READ refMiscBonus2 WRITE setRefMiscBonus2)
    Q_PROPERTY(int will READ will)
    Q_PROPERTY(int willAbilBonus READ willAbilBonus)
    Q_PROPERTY(int willClassBonus READ willClassBonus WRITE setWillClassBonus)
    Q_PROPERTY(int willFeatBonus READ willFeatBonus WRITE setWillFeatBonus)
    Q_PROPERTY(int willMiscBonus1 READ willMiscBonus1 WRITE setWillMiscBonus1)
    Q_PROPERTY(int willMiscBonus2 READ willMiscBonus2 WRITE setWillMiscBonus2)

    // HTI POINTS AND SURGES
    Q_PROPERTY(int maxHitPoints READ maxHitPoints)
    Q_PROPERTY(int baseHitPoints READ baseHitPoints WRITE setBaseHitPoints)
    Q_PROPERTY(int hitPointsPerLevel READ hitPointsPerLevel WRITE setHitPointsPerLevel)
    Q_PROPERTY(int bloodied READ bloodied)
    Q_PROPERTY(int surge READ surge)
    Q_PROPERTY(int surgesPerDay READ surgesPerDay)
    Q_PROPERTY(int surgesPerDayBase READ surgesPerDayBase WRITE setSurgesPerDayBase)

    // SKILL PROPERTIES
    Q_PROPERTY(int acrobatics READ acrobatics)
    Q_PROPERTY(int acrobaticsTrained READ acrobaticsTrained WRITE setAcrobaticsTrained)
    Q_PROPERTY(int arcana READ arcana)
    Q_PROPERTY(int arcanaTrained READ arcanaTrained WRITE setArcanaTrained)
    Q_PROPERTY(int athletics READ athletics)
    Q_PROPERTY(int athleticsTrained READ athleticsTrained WRITE setAthleticsTrained)
    Q_PROPERTY(int bluff READ bluff)
    Q_PROPERTY(int bluffTrained READ bluffTrained WRITE setBluffTrained)
    Q_PROPERTY(int diplomacy READ diplomacy)
    Q_PROPERTY(int diplomacyTrained READ diplomacyTrained WRITE setDiplomacyTrained)
    Q_PROPERTY(int dungeoneering READ dungeoneering)
    Q_PROPERTY(int dungeoneeringTrained READ dungeoneeringTrained WRITE setDungeoneeringTrained)
    Q_PROPERTY(int endurance READ endurance)
    Q_PROPERTY(int enduranceTrained READ enduranceTrained WRITE setEnduranceTrained)
    Q_PROPERTY(int heal READ heal)
    Q_PROPERTY(int healTrained READ healTrained WRITE setHealTrained)
    Q_PROPERTY(int history READ history)
    Q_PROPERTY(int historyTrained READ historyTrained WRITE setHistoryTrained)
    Q_PROPERTY(int insight READ insight)
    Q_PROPERTY(int insightTrained READ insightTrained WRITE setInsightTrained)
    Q_PROPERTY(int intimidate READ intimidate)
    Q_PROPERTY(int intimidateTrained READ intimidateTrained WRITE setIntimidateTrained)
    Q_PROPERTY(int nature READ nature)
    Q_PROPERTY(int natureTrained READ natureTrained WRITE setNatureTrained)
    Q_PROPERTY(int perception READ perception)
    Q_PROPERTY(int perceptionTrained READ perceptionTrained WRITE setPerceptionTrained)
    Q_PROPERTY(int religion READ religion)
    Q_PROPERTY(int religionTrained READ religionTrained WRITE setReligionTrained)
    Q_PROPERTY(int stealth READ stealth)
    Q_PROPERTY(int stealthTrained READ stealthTrained WRITE setStealthTrained)
    Q_PROPERTY(int streetwise READ streetwise)
    Q_PROPERTY(int streetwiseTrained READ streetwiseTrained WRITE setStreetwiseTrained)
    Q_PROPERTY(int thievery READ thievery)
    Q_PROPERTY(int thieveryTrained READ thieveryTrained WRITE setThieveryTrained)
public:
    CharacterRecord();
    ~CharacterRecord();
    void apply(QWidget *sheet) const;

    // CHARACTER DETAILS
    QString name() const { return stringProps["name"]; }
    void setName(const QString &s) { stringProps["name"] = s; }
    QString player() const { return stringProps["player"]; }
    void setPlayer(const QString &s) { stringProps["player"] = s; }
    QString className() const { return stringProps["className"]; }
    void setClassName(const QString &s) { stringProps["className"] = s; }
    QString paragonPath() const { return stringProps["paragonPath"]; }
    void setParagonPath(const QString &s) { stringProps["paragonPath"] = s; }
    QString epicDestiny() const { return stringProps["epicDestiny"]; }
    void setEpicDestiny(const QString & s) { stringProps["epicDestiny"] = s; }
    QString totalXP() const { return stringProps["totalXP"]; }
    void setTotalXP(const QString &s) { stringProps["totalXP"] = s; }
    QString race() const { return stringProps["race"]; }
    void setRace(const QString &s) { stringProps["race"] = s; }
    QString size() const { return stringProps["size"]; }
    void setSize(const QString &s) { stringProps["size"] = s; }
    int age() const { return intProps["age"]; }
    void setAge(int i) { intProps["age"] = i; }
    QString gender() const { return stringProps["gender"]; }
    void setGender(const QString &s) { stringProps["gender"] = s; }
    QString height() const;
    void setHeight(const QString &s);
    int heightInInches() const { return intProps["height"]; }
    void setHeightInInches(int i) { intProps["height"] = i; }
    QString weight() const;
    void setWeight(const QString &s);
    int weightInPounds() const { return intProps["weight"]; }
    void setWeightInPounds(int i) { intProps["weight"] = i; }
    QString alignment() const { return stringProps["alignment"]; }
    void setAlignment(const QString &s) { stringProps["alignment"] = s; }
    QString deity() const { return stringProps["deity"]; }
    void setDeity(const QString &s) { stringProps["deity"] = s; }
    QString company() const { return stringProps["company"]; }
    void setCompany(const QString &s) { stringProps["company"] = s; }
    QString raceAndClass() const { return race() + " " + className(); }

    // INITIATIVE AND LEVEL
    int level() const { return intProps["level"]; }
    void setLevel(int i) { intProps["level"] = i; }
    int initiative() const { return dexMod() + halfLevel() + initiativeMiscMod(); }
    int initiativeMiscMod() const { return intProps["initiativeMiscMod"]; }
    void setInitiativeMiscMod(int i) { intProps["initiativeMiscMod"] = i; }
    int initFeatBonus() const { return intProps["initFeatBonus"]; }
    void setInitFeatBonus(int i) { intProps["initFeatBonus"] = i; }
    int halfLevel() const { return intProps["level"] / 2; }
    int tenPlusHalfLevel() const { return halfLevel() + 10; }

    // BASE STATS
    int strength() const { return intProps["strength"]; }
    void setStrength(int i) { intProps["strength"] = i; }
    int constitution() const { return intProps["constitution"]; }
    void setConstitution(int i) { intProps["constitution"] = i; }
    int dexterity() const { return intProps["dexterity"]; }
    void setDexterity(int i) { intProps["dexterity"] = i; }
    int intelligence() const { return intProps["intelligence"]; }
    void setIntelligence(int i) { intProps["intelligence"] = i; }
    int wisdom() const { return intProps["wisdom"]; }
    void setWisdom(int i) { intProps["wisdom"] = i; }
    int charisma() const { return intProps["charisma"]; }
    void setCharisma(int i) { intProps["charisma"] = i; }

    // STATS AND MODIFIERS
    int strMod() const { return DndData::abilityModifier(strength()); }
    int conMod() const { return DndData::abilityModifier(constitution()); }
    int dexMod() const { return DndData::abilityModifier(dexterity()); }
    int intMod() const { return DndData::abilityModifier(intelligence()); }
    int wisMod() const { return DndData::abilityModifier(wisdom()); }
    int chaMod() const { return DndData::abilityModifier(charisma()); }
    int strModPlusHalfLevel() const { return strMod() + halfLevel(); }
    int conModPlusHalfLevel() const { return conMod() + halfLevel(); }
    int dexModPlusHalfLevel() const { return dexMod() + halfLevel(); }
    int intModPlusHalfLevel() const { return intMod() + halfLevel(); }
    int wisModPlusHalfLevel() const { return wisMod() + halfLevel(); }
    int chaModPlusHalfLevel() const { return chaMod() + halfLevel(); }

    // DEFENCES
    int armourClass() const;
    int armourWeight() const { return intProps["armourWeight"]; }
    void setArmourWeight(int i) { intProps["armourWeight"] = i; }
    int armourPenalty() const { return intProps["armourPenalty"]; }
    void setArmourPenalty(int i) { intProps["armourPenalty"] = i; }
    int acAbilBonus() const;
    int acClassBonus() const { return intProps["acClassBonus"]; }
    void setAcClassBonus(int i) { intProps["acClassBonus"] = i; }
    int acFeatBonus() const { return intProps["acFeatBonus"]; }
    void setAcFeatBonus(int i) { intProps["acFeatBonus"] = i; }
    int acMiscBonus1() const { return intProps["acMiscBonus1"]; }
    void acMiscBonus1(int i) { intProps["acMiscBonus1"] = i; }
    int acMiscBonus2() const { return intProps["acMiscBonus2"]; }
    void acMiscBonus2(int i) { intProps["acMiscBonus2"] = i; }
    int fortitude() const;
    int fortAbilBonus() const { return qMax(strMod(), conMod()); }
    int fortClassBonus() const { return intProps["fortClassBonus"]; }
    void setFortClassBonus(int i) { intProps["fortClassBonus"] = i; }
    int fortFeatBonus() const { return intProps["fortFeatBonus"]; }
    void setFortFeatBonus(int i) { intProps["fortFeatBonus"] = i; }
    int fortMiscBonus1() const { return intProps["fortMiscBonus1"]; }
    void setFortMiscBonus1(int i) { intProps["fortMiscBonus1"] = i; }
    int fortMiscBonus2() const { return intProps["fortMiscBonus2"]; }
    void setFortMiscBonus2(int i) { intProps["fortMiscBonus2"] = i; }
    int reflex() const;
    int refAbilBonus() const { return qMax(dexMod(), intMod()); }
    int refClassBonus() const { return intProps["refClassBonus"]; }
    void setRefClassBonus(int i) { intProps["refClassBonus"] = i; }
    int refFeatBonus() const { return intProps["refFeatBonus"]; }
    void setRefFeatBonus(int i) { intProps["refFeatBonus"] = i; }
    int refMiscBonus1() const { return intProps["refMiscBonus1"]; }
    void setRefMiscBonus1(int i) { intProps["refMiscBonus1"] = i; }
    int refMiscBonus2() const { return intProps["refMiscBonus2"]; }
    void setRefMiscBonus2(int i) { intProps["refMiscBonus2"] = i; }
    int will() const;
    int willAbilBonus() const { return qMax(wisMod(), chaMod()); }
    int willClassBonus() const { return intProps["willClassBonus"]; }
    void setWillClassBonus(int i) { intProps["willClassBonus"] = i; }
    int willFeatBonus() const { return intProps["willFeatBonus"]; }
    void setWillFeatBonus(int i) { intProps["willFeatBonus"] = i; }
    int willMiscBonus1() const { return intProps["willMiscBonus1"]; }
    void setWillMiscBonus1(int i) { intProps["willMiscBonus1"] = i; }
    int willMiscBonus2() const { return intProps["willMiscBonus2"]; }
    void setWillMiscBonus2(int i) { intProps["willMiscBonus2"] = i; }

    // HIT POINTS AND SURGES
    int maxHitPoints() const { return baseHitPoints() + constitution() +
                           (hitPointsPerLevel() * level()); }
    int baseHitPoints() const { return intProps["baseHitPoints"]; }
    void setBaseHitPoints(int i) { intProps["baseHitPoints"] = i; }
    int hitPointsPerLevel() const { return intProps["hitPointsPerLevel"]; }
    void setHitPointsPerLevel(int i) { intProps["hitPointsPerLevel"] = i; }
    int bloodied() const { return maxHitPoints() / 2; }
    int surge() const { return maxHitPoints() / 4; }
    int surgesPerDay() const { return surgesPerDayBase() + conMod(); }
    int surgesPerDayBase() const { return intProps["surgesPerDayBase"]; }
    void setSurgesPerDayBase(int i) { intProps["surgesPerDayBase"] = i; }

    // SKILLS PROPERTIES
    int acrobatics() const { return acrobaticsTrained() + armourPenalty() + dexModPlusHalfLevel(); }
    int acrobaticsTrained() const { return intProps["acrobaticsTrained"]; }
    void setAcrobaticsTrained(int i) { intProps["acrobaticsTrained"] = i; }
    int arcana() const { return acrobaticsTrained() + intModPlusHalfLevel(); }
    int arcanaTrained() const { return intProps["arcanaTrained"]; }
    void setArcanaTrained(int i) { intProps["arcanaTrained"] = i; }
    int athletics() const { return athleticsTrained() + armourPenalty() + strModPlusHalfLevel(); }
    int athleticsTrained() const { return intProps["athleticsTrained"]; }
    void setAthleticsTrained(int i) { intProps["athleticsTrained"] = i; }
    int bluff() const { return bluffTrained() + chaModPlusHalfLevel(); }
    int bluffTrained() const { return intProps["bluffTrained"]; }
    void setBluffTrained(int i) { intProps["bluffTrained"] = i; }
    int diplomacy() const { return diplomacyTrained() + chaModPlusHalfLevel(); }
    int diplomacyTrained() const { return intProps["diplomacyTrained"]; }
    void setDiplomacyTrained(int i) { intProps["diplomacyTrained"] = i; }
    int dungeoneering() const { return dungeoneeringTrained() + armourPenalty() + wisModPlusHalfLevel(); }
    int dungeoneeringTrained() const { return intProps["dungeoneeringTrained"]; }
    void setDungeoneeringTrained(int i) { intProps["dungeoneeringTrained"] = i; }
    int endurance() const { return enduranceTrained() + armourPenalty() + conModPlusHalfLevel(); }
    int enduranceTrained() const { return intProps["enduranceTrained"]; }
    void setEnduranceTrained(int i) { intProps["enduranceTrained"] = i; }
    int heal() const { return healTrained() + wisModPlusHalfLevel(); }
    int healTrained() const { return intProps["healTrained"]; }
    void setHealTrained(int i) { intProps["healTrained"] = i; }
    int history() const { return historyTrained() + intModPlusHalfLevel(); }
    int historyTrained() const { return intProps["historyTrained"]; }
    void setHistoryTrained(int i) { intProps["historyTrained"] = i; }
    int insight() const { return insightTrained() + wisModPlusHalfLevel(); }
    int insightTrained() const { return intProps["insightTrained"]; }
    void setInsightTrained(int i) { intProps["insightTrained"] = i; }
    int intimidate() const { return intimidateTrained() + chaModPlusHalfLevel(); }
    int intimidateTrained() const { return intProps["intimidateTrained"]; }
    void setIntimidateTrained(int i) { intProps["intimidateTrained"] = i; }
    int nature() const { return natureTrained() + wisModPlusHalfLevel(); }
    int natureTrained() const { return intProps["natureTrained"]; }
    void setNatureTrained(int i) { intProps["natureTrained"] = i; }
    int perception() const { return perceptionTrained() + dexModPlusHalfLevel(); }
    int perceptionTrained() const { return intProps["perceptionTrained"]; }
    void setPerceptionTrained(int i) { intProps["perceptionTrained"] = i; }
    int religion() const { return religionTrained() + dexModPlusHalfLevel(); }
    int religionTrained() const { return intProps["religionTrained"]; }
    void setReligionTrained(int i) { intProps["religionTrained"] = i; }
    int stealth() const { return stealthTrained() + armourPenalty() + dexModPlusHalfLevel(); }
    int stealthTrained() const { return intProps["stealthTrained"]; }
    void setStealthTrained(int i) { intProps["stealthTrained"] = i; }
    int streetwise() const { return streetwiseTrained() + dexModPlusHalfLevel(); }
    int streetwiseTrained() const { return intProps["streetwiseTrained"]; }
    void setStreetwiseTrained(int i) { intProps["streetwiseTrained"] = i; }
    int thievery() const { return thieveryTrained() + armourPenalty() + dexModPlusHalfLevel(); }
    int thieveryTrained() const { return intProps["thieveryTrained"]; }
    void setThieveryTrained(int i) { intProps["thieveryTrained"] = i; }

private:
    QMap<QString, int> intProps;
    QMap<QString, QString> stringProps;
};

#endif // CHARACTERRECORD_H
